package com.wb.utils

import com.wb.utils.UnicodeUtil.Companion.toHexString
import com.google.gson.Gson
import org.apache.commons.codec.binary.Base64
import org.apache.commons.codec.binary.Hex
import org.apache.commons.lang3.StringUtils
import java.math.BigInteger
import java.nio.charset.Charset
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import java.security.cert.CertificateException
import java.util.*
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
import kotlin.collections.HashMap
import kotlin.experimental.and

/**
 * 网抑云 AES 编码(参数加密)
 *
 * @author 祁雪
 */
class WangYiAESEncrypt {

    companion object {
        val modulus =
            "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7";

        val nonce = "0CoJUm6Qyw8W8jud";

        val pubKey = "010001";
//        val pubKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgtQn2JZ34ZC28NWYpAUd98iZ37BUrX/aKzmFbt7clFSs6sXqHauqKWqdtLkF2KexO40H1YTX8z2lSgBBOAxLsvaklV8k4cBFK9snQXE9/DDaFt6Rr7iVZMldczhC0JNgTz+SHXT6CBHuX3e9SdB1Ua44oncaTWz7OBGLbCiK45wIDAQAB";

        val eapiKey = "e82ckenh8dichen8";

        /**
         * 创建秘钥
         * @param size  位数
         * @return
         */
        fun createSecreKey(size: Int): String {
            val keys = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

            var key = ""
            for (i in 0 until size) {
                val pos = Math.floor(Math.random() * keys.length).toInt()
                key = key + keys[pos]
            }

            return key
        }

        /**
         * 字符串转换成十六进制字符串
         */
        fun str2HexStr(str: String): String {
            val chars = "0123456789ABCDEF".toCharArray()
            val sb = StringBuilder()
            val bs = str.toByteArray()
            var bit: Int? = null
            for (i in 0 until bs.size) {
                bit = (bs[i] and 0x0f0.toByte()).toInt() shr 4
                sb.append(chars[bit]);
                bit = (bs[i] and 0x0f).toInt();
                sb.append(chars[bit]);
            }
            return sb.toString()
        }

        fun strToHexStr(str: String): String {
            val chars = str.toCharArray()

            val hex = StringBuffer()

            for (i in 0 until chars.size) {
                hex.append(chars[i].toInt().toHexString())
            }

            return hex.toString()
        }

        /**
         * aes加密
         * @param sSrc
         * @param sKey
         * @return
         * @throws Exception
         */
        @kotlin.jvm.Throws(Exception::class)
        fun aesEncrypt(sSrc: String, sKey: String, mode: String): String {
            val cipher = Cipher.getInstance("AES/${mode}/PKCS5Padding")
            val raw = sKey.toByteArray();
            val skeySpec = SecretKeySpec(raw, "AES")
            //使用CBC模式，需要一个向量iv，可增加加密算法的强度
            if ("ECB".equals(mode)) {
                cipher.init(Cipher.ENCRYPT_MODE, skeySpec)
            } else {
                val iv = IvParameterSpec("0102030405060708".toByteArray())
                cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv)
            }
            val encrypted = cipher.doFinal(sSrc.toByteArray())

            //此处使用BASE64做转码 或 HEX 16进制
            return if ("ECB".equals(mode)) {
                println("encrypted: ${Hex.encodeHexString(encrypted)}")
                zfill(Hex.encodeHexString(encrypted), 256)
            } else Base64().encodeToString(encrypted)
        }


        fun md5Encode(text: String): String {
            try {
                //获取md5加密对象
                val instance: MessageDigest = MessageDigest.getInstance("MD5")

                instance.update(text.toByteArray())

                return BigInteger(1, instance.digest()).toString(16);

            } catch (e: NoSuchAlgorithmException) {
                e.printStackTrace()
            }

            return ""
        }

        /**
         * 截取长度
         * @param str
         * @param size
         * @return
         */
        fun zfill(str: String, size: Int): String {
            var strx = str
            while (strx.length < size) {
                strx = "0" + strx;
            }
            return strx;
        }

        /**
         * 16进制字符串转字节数组
         * @param hexString
         * @return
         */
        fun hexToBytes(hexString: String): ByteArray? {
            if (hexString.isEmpty()) {
                return null;
            }
            val length = hexString.length / 2
            val hexChars: CharArray = hexString.toCharArray()
            val bytes: ByteArray = ByteArray(length)

            val hexDigits = "0123456789abcdef";
            for (i in 0 until length) {
                val pos = i * 2
                val h = hexDigits.indexOf(hexChars[pos]) shl 4
                val l = hexDigits.indexOf(hexChars[pos + 1])
                if (h == -1 || l == -1) { // 非16进制字符
                    return null;
                }
                bytes[i] = (h or l).toByte()
            }
            return bytes;
        }

        /**
         * rsa加密算法
         * @param text
         * @param pubKey
         * @param modulus
         * @return
         */
        fun rsaEncrypt(text: String, pubKey: String, modulus: String): String {
            /*val list = Arrays.asList(text.split(""))
            Collections.reverse(list)*/
            val _text = text.reversed()
//            val _text = StringUtils.join(list, "")
            /*println(_text)
            println(list.joinToString(separator = ""))*/

            val biText = BigInteger(1, _text.toByteArray())
            val biEx = BigInteger(1, hexToBytes(pubKey))
            val biMod = BigInteger(1, hexToBytes(modulus))
            val biRet = biText.modPow(biEx, biMod).toString(16)

            return zfill(biRet, 256)
        }

        /**
         * 网易云音乐参数加密
         * @param paras
         * @return
         * @throws Exception
         */
        @kotlin.jvm.Throws(Exception::class)
        fun encryptWY(paras: String): HashMap<String, String> {
            println(paras)
            val secKey = createSecreKey(16)
            val encText = aesEncrypt(aesEncrypt(paras, nonce, "CBC"), secKey, "CBC")
            val encSecKey = rsaEncrypt(secKey, pubKey, modulus)
            val datas = hashMapOf<String, String>(
                "params" to encText,
                "encSecKey" to encSecKey
            )
            return datas
        }
    }

}

fun main() {
    /*val data = hashMapOf<String, Any>(
        "rid" to "1441860073",
        // 1: 单曲, 10: 专辑, 100: 歌手, 1000: 歌单, 1002: 用户, 1004: MV, 1006: 歌词, 1009: 电台, 1014: 视频
//        "type" to 1,
        "beforeTime" to 0,
        "limit" to 10,
        "offset" to 0
    )*/
    val data = hashMapOf<String, Any>(
        "c" to Gson().toJson(
            arrayListOf(
                mapOf(
                    "id" to 25713016
                )
            )
        ),
//        "br" to 999000,
        "csrf_token" to ""
    )
    println(data)
    val header = hashMapOf(
        "osver" to "",
        "deviceId" to "",
        "appver" to "8.0.0",
        "versioncode" to "140",
        "mobilename" to "",
        "buildver" to Date().time.toString().substring(0, 10),
        "resolution" to "1920x1080",
        "resolution" to "1920x1080",
        "__csrf" to "",
        "os" to "pc",
        "channel" to null,
        "requestId" to "${Date().time}_${Math.floor(Math.random() * 1000)}".padStart(4, '0')
    )
//    data.put("header", header)
    println(
        Gson().toJson(
            data
        )
    )
    // 检查音乐是否能够播放 参数数据 start
    var dataStr =
        "nobody/api/song/enhance/player/urluse${Gson().toJson(data)}md5forencrypt"
    println(dataStr)
    val md5 = WangYiAESEncrypt.md5Encode(dataStr)
    println(md5)
    dataStr =
        "/api/song/enhance/player/url-36cd479b6b5-${Gson().toJson(data)}-36cd479b6b5-${
            md5
        }"
    println(dataStr)

    val params = WangYiAESEncrypt.aesEncrypt(dataStr, WangYiAESEncrypt.eapiKey, "ECB").toUpperCase()

    println(params)
    // 检查音乐是否能够播放 参数数据 end

    val resultMap = WangYiAESEncrypt.encryptWY(
        Gson().toJson(data)
    )
    println(resultMap)
//    println(WangYiAESEncrypt.md5Encode("bcl201314"))

}